package com.chiancloud.shield.providers;

import com.chiancloud.shield.common.ShieldKeys;
import com.chiancloud.shield.common.ShieldXmlConfKeys;
import com.chiancloud.shield.core.exception.BadClusterStateException;
import com.chiancloud.shield.core.exception.ShieldException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by wanghui on 14-8-20.
 */
public abstract class ShieldProviderFactory extends Configured {

    public static final String DEFAULT_CLUSTER_TYPE = AgentKeys.PROVIDER_AGENT;

    protected static final Logger log =
            LoggerFactory.getLogger(ShieldProviderFactory.class);
    public static final String PROVIDER_NOT_FOUND =
            "Unable to find provider of application type %s";

    public ShieldProviderFactory(Configuration conf) {
        super(conf);
    }

    protected ShieldProviderFactory() {
    }

    public abstract AbstractClientProvider createClientProvider();

    public abstract ProviderService createServerProvider();


    public static ShieldProviderFactory createSliderProviderFactory(String application) throws
            ShieldException {
        Configuration conf = loadSliderConfiguration();
        if (application == null) {
            application = DEFAULT_CLUSTER_TYPE;
        }
        String providerKey =
                String.format(ShieldXmlConfKeys.KEY_PROVIDER, application);
        if (application.contains(".")) {
            log.debug("Treating {} as a classname", application);
            String name = "classname.key";
            conf.set(name, application);
            providerKey = name;
        }

        Class<? extends ShieldProviderFactory> providerClass;
        try {
            providerClass = conf.getClass(providerKey, null, ShieldProviderFactory.class);
        } catch (RuntimeException e) {
            throw new BadClusterStateException(e, "Failed to load provider %s: %s", application, e);
        }
        if (providerClass == null) {
            throw new BadClusterStateException(PROVIDER_NOT_FOUND, application);
        }

        Exception ex;
        try {
            ShieldProviderFactory providerFactory = providerClass.newInstance();
            providerFactory.setConf(conf);
            return providerFactory;
        } catch (Exception e) {
            ex = e;
        }
        //by here the operation failed and ex is set to the value
        throw new BadClusterStateException(ex,
                "Failed to create an instance of %s : %s",
                providerClass,
                ex);
    }

    public static Configuration loadSliderConfiguration() {
        Configuration conf = new Configuration();
        conf.addResource(ShieldKeys.SHIELD_XML);
        return conf;
    }
}
